#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
#include <stdint.h>
#include <unistd.h>

#define errExit(msg) do { perrer(msg); exit(EXIT_FAILURE);} \

#define handle_error_en(en, msg) do { errno = en; perror(msg); exit(EXIT_FAILURE);} while(0)

#define MS_PER_SEC 1000000
/*
 * in linux get page size use
 *
 * $ getconf PAGESIZE
 *
 * page number
 *
 * try times
 *
 * */


double run_trials(int page_size, int num_pages, int trials);

int main(int argc, char ** argv){
	
	if(argc != 3){
		fprintf(stderr, "Usage: %s page_number try_times!\n",
										argv[0]);
		exit(EXIT_FAILURE);
	}
	
	int ret;
	int page_size;
	cpu_set_t cpuset;

	/* Set affinity mask to CPU 0 */
	CPU_ZERO(&cpuset);

	CPU_SET(0, &cpuset);

	ret = sched_setaffinity(0, sizeof(cpuset), &cpuset);
	if(ret != 0)
					handle_error_en(ret, "pthread_setaffinity_np");

	int NUMPAGES = atoi(argv[1]);
	int NUMTRAILS = atoi(argv[2]);
	page_size = getpagesize();

  double total = run_trials(page_size, NUMPAGES, NUMTRAILS);
  printf("%ld\t%ld\t%f\n", NUMPAGES, NUMTRAILS, total);

	return 0;
}
double run_trials(int page_size, int num_pages, int trials)
{
    struct timeval start, end;
    uint64_t trial_time = 0;
    int elems, jump, i, j;
		uint64_t tod1, tod2;
    int *arr;

		float r = 0;
    /* initialise an array big enough to span num_pages */
    elems = (page_size * num_pages) / sizeof(int);
    arr = (int*) calloc(elems, sizeof(int));

    /* distance to next page */
    jump = page_size / sizeof(int);

    /* run trials */
    tod1 = gettimeofday(&start, NULL);  // start time
    for (j = 0; j < trials; j++) {
        for (i = 0; i < num_pages * jump; i += jump) {
            arr[i] += 1;                        // page access
						r += arr[i];
        }
    }
    tod2 = gettimeofday(&end, NULL);    // end time
    if (tod1 == -1 || tod2 == -1) {
        fprintf(stderr, "failed benchmarking time\n");
        exit(EXIT_FAILURE);
    }
    trial_time = (end.tv_sec - start.tv_sec) * MS_PER_SEC + end.tv_usec - start.tv_usec;
    free(arr);
		printf("%c\n", (char)r);
    return trial_time / (double) (num_pages * trials);
}
